#include<stdio.h>
#include<iostream>
#include<vector>
#include<semaphore.h>   //信号量
#include<pthread.h>

//使用信号量实现环形队列 --- 生产者与消费者模型
#define MAX_QUEUE 5

template<class T>
class RingQueue{
private:
  std::vector<int> _arry;
  int _read_step;         //读取位置
  int _write_step;        //写入位置
  int _capacity;         //容量
  sem_t _sem_idle;       //信号量本质是一个计数器---记录空闲位置个数
  sem_t _sem_data;       //记录数据资源的个数
  sem_t _sem_lock;       //锁资源，实现互斥
public:
  RingQueue(int capacity=MAX_QUEUE):_capacity(capacity),_arry(capacity),_read_step(0),_write_step(0){
    sem_init(&_sem_idle,0,capacity);      //空闲地址初始化个数 = 环形队列容量
    sem_init(&_sem_data,0,0);          //数据空间初始化为 0，一开始没有数据资源
    sem_init(&_sem_lock,0,1);      //锁资源初始化为1 
  }
  ~RingQueue(){
     sem_destroy(&_sem_idle);
     sem_destroy(&_sem_data);
     sem_destroy(&_sem_lock);
  }

  bool Push(T& data){
     //首先判断环形队列中空闲资源是否存在
     sem_wait(&_sem_idle); //判断是否存在空闲资源，没有则阻塞，P 操作 --- 正确返回则计数-1表示空闲空间少了一个
     sem_wait(&_sem_lock);   //加锁要放在判断之后 --- 倘若没有空闲空间就会陷入休眠，没有解锁操作
     //存在空闲空间，则消费者进行 V 操作 ---- 表示数据资源多了一个
     _arry[_write_step]=data;
     _write_step = (_write_step+1)%_capacity;   //数据资源增加一个，写入位置向后移动一个
     sem_post(&_sem_lock);   //解锁
     sem_post(&_sem_data);   //V 操作，数据资源+1
     return true; 
     
  }

  bool Pop(T* data){ 
      //首先判断是否存在数据资源
      sem_wait(&_sem_data);
      sem_wait(&_sem_lock);   //存在数据资源，进行P操作，加锁
      //读取数据资源
      *data=_arry[_read_step];
      _read_step=(_read_step+1)%_capacity;
      sem_post(&_sem_lock);     //读取数据之后进行 V 操作，解锁
      sem_post(&_sem_idle);    //V 操作，空闲资源增加一个
      return true;
  }
};

int data=0;

void* Product(void*arg)
{
  RingQueue<int> *q=(RingQueue<int>*)arg;
  while(1){ 
     //生产者线程---存入数据 
     q->Push(data);
     printf("---- %p 线程存入数据 %d\n",pthread_self(),data++);
  }
  return NULL;
}

void* Constom(void*arg)
{
  RingQueue<int> *q=(RingQueue<int>*)arg;
  while(1){ 
     //消费者线程---读取数据 
     int data;
     q->Pop(&data);
     printf("++++ %p 线程读取数据 %d\n",pthread_self(),data);
  }
  return NULL;
}

#define MAX_USER 4
int main()
{
  RingQueue<int> q;  //创建一个环形队列
  //创建线程
  pthread_t pro_tid[MAX_USER],con_tid[MAX_USER];
  int ret;
  for(int i=0;i<MAX_USER;++i){
    ret=pthread_create(&pro_tid[i],NULL,Product,(void*)&q);
    if(ret!=0){
      perror("pthread_create error!\n");
      return -1;
    }
    ret=pthread_create(&con_tid[i],NULL,Constom,(void*)&q);
    if(ret!=0){
      perror("pthread_create error!\n");
      return -1;
    }
  }
  //线程等待
  for(int i=0;i<MAX_USER;++i){  
    pthread_join(pro_tid[i],NULL);
    pthread_join(con_tid[i],NULL);
  }
  return 0;
}


